/*------------------------------------------------------*/
/*                                                      */
/* Copyright (C)	sky-mobi.com                        */
/* All rights reserved                                  */
/*                                                      */
/* Author   tristan.yang                                */
/*                                                      */
/* History  2011-5-13 created                           */
/*                                                      */
/*------------------------------------------------------*/

#ifndef __RING_BUFFER_H__
#define __RING_BUFFER_H__

//#include "database.h"
#include "RtBase.h"
#include "RtMutex.h"
#include "RtReferenceControl.h"
#include "RtUtilTemplates.h"
#include <deque>
#include <map>

#define str_SSP_Packet	"CSSPPacket"

class CStreamPacket;
class CPacketFactory;

typedef std::deque<CStreamPacket*>			DeqPacketType;
typedef DeqPacketType::iterator				DeqPacketType_Iter;

typedef std::map<std::string, CPacketFactory*>	MapFactoryType;
typedef MapFactoryType::iterator				MapFactory_Iter;


//////////////////////////////////////////////////////////////////////////
// Class CStreamPacket
class CStreamPacket
{
public:
	CStreamPacket(): m_pBuffer(NULL), m_llseqId(0), m_iRef(0){}
	virtual ~CStreamPacket(){
		if (m_pBuffer){ 
			delete [] m_pBuffer;
		//	RT_INFO_TRACE("CStreamPacket::~CStreamPacket delete");
		}
	}

	virtual INT addData(LPCSTR pData, DWORD nDataLen) = 0;
	virtual LPSTR getData(DWORD& nLen) const = 0;
	virtual INT getDataLen() const = 0;

	virtual bool isKeyFrame() const { return false; }
	virtual bool isPartialFrame() const { return false; }

	virtual DWORD getMediaType() const { return -1; }

	void setSeq(LONGLONG seq) { m_llseqId = seq; }
	LONGLONG getSeq() const { return m_llseqId; }

	INT addRef(void);
	INT releaseRef(void);

protected:
	LPSTR			m_pBuffer;
	DWORD			m_dwLen;
	std::string		m_strData;
	LONGLONG		m_llseqId;
	INT				m_iRef;
};

//////////////////////////////////////////////////////////////////////////
// Class CPacketFactory
class CPacketFactory
{
public:
	CStreamPacket* CreatePacket();
	void ReleasePacket(CStreamPacket* pPacket);

	virtual ~CPacketFactory(){};
	friend class CPacketFactoryInitializer;

private:
	virtual CStreamPacket* Create() = 0;
	virtual void Release(CStreamPacket* pPacket) = 0;

protected:
	DeqPacketType m_freePacketDeque;
};

//////////////////////////////////////////////////////////////////////////
// Class CFactoryCreator
class CFactoryCreator
{
public:
	static CFactoryCreator* Instance();

	CPacketFactory* GetFactory(std::string strFactoryName);
	void ReleaseFactory(std::string strFactoryName);

protected:
	friend class CRtSingletonT<CFactoryCreator>;
	CFactoryCreator(){}
	virtual ~CFactoryCreator();

private:
	std::map<std::string, CPacketFactory*> m_FactoryMap;
};
typedef CRtSingletonT<CFactoryCreator> CFactoryCreatorSingleton;


//////////////////////////////////////////////////////////////////////////
// Class CSSPPacket
class CSSPPacket: public CStreamPacket
{
public:
	virtual INT addData(LPCSTR pData, DWORD nDataLen);
	virtual LPSTR getData(DWORD& nLen) const;
	virtual INT getDataLen() const;
	virtual bool isKeyFrame() const;

	virtual DWORD getMediaType() const;

	inline INT GetHeadeSsize() const {return 0;}

	CSSPPacket():CStreamPacket(){};
	virtual ~CSSPPacket(){};

	class Factory: public CPacketFactory
	{
	public:
		CStreamPacket* Create();
		void Release(CStreamPacket* pPacket);
		virtual ~Factory();
	private:
		typedef CRtMutexThread	MutexType;
		MutexType	m_mutex;
	};

private:
	friend class CPacketFactoryInitializer;
	friend class Factory;
};

//////////////////////////////////////////////////////////////////////////
// Class CStreamRingBuffer
class CStreamRingBuffer
{
public:
	typedef std::deque<CStreamPacket*>::size_type size_type;
	typedef std::deque<CStreamPacket*>::value_type value_type;
	typedef std::deque<CStreamPacket*>::iterator iter_type;
	typedef std::deque<CStreamPacket*>::reverse_iterator rever_iter_type;
private:
	typedef CRtMutexThread	MutexType;
	MutexType				m_Mutex;

public:
	size_type size() const
	{
		//CRtMutexGuardT<MutexType> theGuard(m_Mutex);
		return m_Buffer.size();
	}
	void resize(DWORD nSize);
	bool empty() const;
	bool full() const;
	bool pushdata(LPCSTR pdata, INT ilen);
	bool popdata(LPSTR& pOutData, 
				DWORD& nOutSize, 
				LONGLONG& llSeq, 
				bool bFindIFrame, 
				bool& bIsEndFrame);

	bool push(value_type T);
	bool pop(value_type& T, 
			LONGLONG llSeq, 
			bool bFindIFrame, 
			bool& bIsEndFrame);

	void clear();
	void addseq();
	void SaveRawData(LPBYTE pbuf, int isize);

public:
	CStreamRingBuffer(DWORD nMaxSize, CPacketFactory* pFactory);
	~CStreamRingBuffer(void){
		RT_INFO_TRACE_THIS("~CStreamRingBuffer");
		clear();
	}

	CStreamRingBuffer& operator = (CStreamRingBuffer& ring)
	{
		if(this == &ring)
		{
			return *this;
		}
		m_nMaxSize = ring.m_nMaxSize;
		m_llSequence = ring.m_llSequence;
		return *this;
	}

private:
	CPacketFactory*			m_pFactory;
	std::deque<CStreamPacket*>	m_Buffer;
	INT						m_nCurrentSize;
	DWORD					m_nMaxSize;
	LONGLONG				m_llSequence;
};

//////////////////////////////////////////////////////////////////////////
// Class CFileRingBuffer
class CFileRingBuffer
{
public:
	INT capacity() const;
	INT size() const;
	LPSTR ptr() const;
	
	bool empty() const;
	bool full() const;
	bool push(LPCSTR pData, INT nDataSize);
	bool pop(LPSTR& pOutData, DWORD& nOutSize, DWORD nPopPos, DWORD nPopSize, bool& bIsEndFrame);
	void resize(DWORD nSize);
	void clear();

	CFileRingBuffer(DWORD nSize);
	virtual ~CFileRingBuffer(void){
		clear();
	}

protected:
	DWORD		m_nCurrentSize;
	DWORD		m_nMaxBufferSize;
	LPSTR		m_pBuffer;
	typedef CRtMutexThread	MutexType;
	MutexType	m_Mutex;
};

#endif//__RING_BUFFER_H__
